import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacpp.PointerPointer;
import org.bytedeco.llvm.LLVM.*;

import java.util.ArrayList;
import java.util.List;

import static org.bytedeco.llvm.global.LLVM.*;

public class MyVisitor extends SysYParserBaseVisitor<Pointer> {
    private final ParseTreeProperty<BlockInBlock> blockInBlocks = new ParseTreeProperty();
    private final ParseTreeProperty<LLVMBasicBlockRef> trueBlock = new ParseTreeProperty();
    private final ParseTreeProperty<LLVMBasicBlockRef> falseBlock = new ParseTreeProperty();
    private final ParseTreeProperty<Pointer> values = new ParseTreeProperty();
    private final ParseTreeProperty<LLVMBasicBlockRef> blockValue = new ParseTreeProperty();
    private final ParseTreeProperty<LLVMBasicBlockRef> whileNextBlock = new ParseTreeProperty<>();
    private final ParseTreeProperty<Integer> valueOfValues = new ParseTreeProperty();
    private LLVMModuleRef module = null;
    private LLVMBuilderRef builder = null;
    private LLVMTypeRef i32Type = LLVMInt32Type();

    private Scope globalScope = null;
    private Scope currentScope = null;

    MyVisitor(LLVMModuleRef module, LLVMBuilderRef builder) {
        this.module = module;
        this.builder = builder;
    }

    private static String IntegerCorrextion(String text) {
        //将十六进制、八进制转化成十进制
        if (text.startsWith("0x") || text.startsWith("0X") || text.startsWith("0")) {
            Integer temp = Integer.decode(text);
            return String.valueOf(temp);
        } else {
            return text;
        }
    }

    @Override
    public Pointer visitProgram(SysYParser.ProgramContext ctx) {
        printTest("program");
        //生成一个全局Scope
        this.globalScope = new BaseScope("globalScope", null);
        this.currentScope = this.globalScope;
        return super.visitProgram(ctx);
    }

    @Override
    public Pointer visitFuncType(SysYParser.FuncTypeContext ctx) {
        printTest("funcType");
        //返回函数返回值
        if (ctx.getText().equals("int")) {
            return LLVMInt32Type();
        } else {
            return LLVMVoidType();
        }
    }

    @Override
    public Pointer visitFuncDef(SysYParser.FuncDefContext ctx) {
        printTest("funcdef");
        //获取函数名称
        String functionName = ctx.IDENT().getText();
        //得到返回参数
        LLVMTypeRef returnType = (LLVMTypeRef) this.visitFuncType(ctx.funcType());
        //得到参数类型
        PointerPointer<Pointer> argumentTypes = null;
        if (ctx.funcFParams() == null) {
            argumentTypes = new PointerPointer<>(0);
        } else {
            argumentTypes = (PointerPointer<Pointer>) this.visitFuncFParams(ctx.funcFParams());
        }
        //计算参数数量
        int numOfArgument = (int) argumentTypes.capacity();
        //生成函数类型
        LLVMTypeRef ft = LLVMFunctionType(returnType, argumentTypes, /* argumentCount */ numOfArgument, /* isVariadic */ 0);
        //生成函数，即向之前创建的module中添加函数
        LLVMValueRef function = LLVMAddFunction(module, /*functionName:String*/functionName, ft);
        //将函数名写入scope
        currentScope.define(functionName, function);
        //切换到函数scope
        this.currentScope = new BaseScope(functionName, this.currentScope);
        //访问block
        this.visitBlock(ctx.block());
        return function;
    }

    @Override
    public Pointer visitFuncFParams(SysYParser.FuncFParamsContext ctx) {
        int tempNum = 0;
        printTest("funcfparams");
        //返回函数参数
        int numOfFuncParams = ctx.funcFParam().size();
        PointerPointer<Pointer> argumentTypes = new PointerPointer<>(numOfFuncParams);
        for (SysYParser.FuncFParamContext fCtx : ctx.funcFParam()) {
            if (ctx.funcFParam().size() == 0) {
                argumentTypes.put(tempNum, i32Type);
            } else {
                argumentTypes.put(tempNum, LLVMPointerType(LLVMArrayType(i32Type, 0), 0));
            }
            tempNum++;
        }
        return argumentTypes;
    }

    @Override
    public Pointer visitBlock(SysYParser.BlockContext ctx) {
        printTest("block");
        //区分是函数Block还是函数内Block
        if (ctx.parent instanceof SysYParser.FuncDefContext) {
            //函数Block
            this.funcBlock(ctx);
        } else {
            //在llvm内加入该模块
            LLVMValueRef function = this.getFunc(ctx);
            //通过如下语句在函数中加入基本块
            String blockName;
            try {
                blockName = getStmtType(ctx) + ":" + getStmtStmtType(ctx);
            } catch (Exception e) {
                blockName = getStmtType(ctx);
            }

            LLVMBasicBlockRef localBlock = LLVMAppendBasicBlock(function, /*blockName:String*/blockName);
            LLVMPositionBuilderAtEnd(builder, localBlock);//后续生成的指令将追加在localBlock的后面
            //不要忘了开启新的scope
            blockValue.put(ctx, localBlock);
            currentScope = new BaseScope("LocalScope", currentScope);
            currentScope.define("block", localBlock);
            blockInBlocks.put(ctx, new BlockInBlock(localBlock));
        }
        this.visitChildren(ctx);
        //退出block
        //如果是void函数且没有return则自动补齐return
        if (ctx.parent instanceof SysYParser.FuncDefContext) {
            //函数Block
            voidReturn(ctx);
        }
        //退出
        currentScope = currentScope.getEnclosingScope();
        //如果是if while的block，则需要无条件跳转
        if (ctx.getParent().getParent() instanceof SysYParser.ConditionStmtContext || ctx.getParent().getParent() instanceof SysYParser.WhileStmtContext) {
            LLVMBasicBlockRef llvmBasicBlockRef = blockValue.get(ctx.getParent().getParent());
            LLVMBuildBr(builder, llvmBasicBlockRef);
        }
        return null;
    }

    private String getStmtType(ParserRuleContext ctx) {
        do {
            ctx = ctx.getParent();
        } while (!(ctx instanceof SysYParser.WhileStmtContext || ctx instanceof SysYParser.ConditionStmtContext));
        if (ctx instanceof SysYParser.WhileStmtContext) {
            return "while";
        } else {
            return "if";
        }
    }

    private String getStmtStmtType(ParserRuleContext ctx) {
        do {
            ctx = ctx.getParent();
        } while (!(ctx instanceof SysYParser.WhileStmtContext || ctx instanceof SysYParser.ConditionStmtContext));
        do {
            ctx = ctx.getParent();
        } while (!(ctx instanceof SysYParser.WhileStmtContext || ctx instanceof SysYParser.ConditionStmtContext));
        if (ctx instanceof SysYParser.WhileStmtContext) {
            return "while";
        } else {
            return "if";
        }
    }

    private void voidReturn(SysYParser.BlockContext ctx) {
        SysYParser.FuncDefContext funcDefContext = (SysYParser.FuncDefContext) ctx.getParent();
        if (funcDefContext.funcType().getText().equals("void")) {
            boolean hasReturn = false;
            for (SysYParser.BlockItemContext blockItemContext : ctx.blockItem()) {
                if (blockItemContext.stmt() instanceof SysYParser.ReturnStmtContext) {
                    hasReturn = true;
                }
            }
            if (!hasReturn) {
                LLVMBuildRet(builder, /*result:LLVMValueRef*/null);
            }
        }
    }

    private LLVMValueRef getFunc(ParserRuleContext ctx) {
        ParserRuleContext funcDef = ctx;
        do {
            funcDef = funcDef.getParent();
        } while (!(funcDef instanceof SysYParser.FuncDefContext));
        String funcName = ((SysYParser.FuncDefContext) funcDef).IDENT().getText();
        return (LLVMValueRef) currentScope.resolve(funcName);
    }

    //该函数用以处理函数Block的函数参数
    private Pointer funcBlock(SysYParser.BlockContext ctx) {
        //通过符号表获取函数LLVM值
        SysYParser.FuncDefContext funcDefContext = (SysYParser.FuncDefContext) ctx.parent;
        String funcName = funcDefContext.IDENT().getText();
        LLVMValueRef function = (LLVMValueRef) currentScope.resolve(funcName);
        //通过如下语句在函数中加入基本块
        String blockName = funcName + "Entry";
        LLVMBasicBlockRef funcBlock = LLVMAppendBasicBlock(function, /*blockName:String*/blockName);
        blockValue.put(ctx, funcBlock);
        //选择要在哪个基本块后追加指令
        LLVMPositionBuilderAtEnd(builder, funcBlock);//后续生成的指令将追加在funcBlock的后面
        currentScope.getEnclosingScope().define("funcBlock", funcBlock);
        currentScope.define("block", funcBlock);
        blockInBlocks.put(ctx, new BlockInBlock(funcBlock));
        //处理函数的参数（如果有的话）
        this.setAllParams(ctx);
        return null;
    }

    //该函数用以函数参数的LLVM代码生成以及符号表写入
    private void setAllParams(SysYParser.BlockContext ctx) {
        //得到Block对应的函数
        SysYParser.FuncDefContext funcDefContext = (SysYParser.FuncDefContext) ctx.parent;
        String funcName = funcDefContext.IDENT().getText();
        LLVMValueRef function = (LLVMValueRef) currentScope.resolve(funcName);
        //判断函数参数个数
        int numPfParams = LLVMCountParams(function);
        if (numPfParams == 0) {
            //没有参数
            return;
        }
        //处理该函数的参数，包括生成对应LLVM代码，写入符号表
        List<LLVMValueRef> pointerList = new ArrayList<>();
        for (int i = 0; i < numPfParams; i++) {
            //获取函数的参数
            LLVMValueRef param = LLVMGetParam(function, /* parameterIndex */i);
            //获取函数的参数名
            SysYParser.FuncFParamsContext funcFParamsContext = funcDefContext.funcFParams();
            String paramName = funcFParamsContext.funcFParam().get(i).IDENT().getText();
            //连续申请一块能存放int型的内存
            LLVMValueRef pointer = LLVMBuildAlloca(builder, i32Type, /*pointerName:String*/paramName);
            //将函数的参数写入符号表
            currentScope.define(paramName, pointer);
            pointerList.add(pointer);
        }
        //将参数数值存入内存
        for (int i = 0; i < numPfParams; i++) {
            //获取内存指针
            LLVMValueRef pointer = pointerList.get(i);
            //获取对应的函数的参数
            LLVMValueRef param = LLVMGetParam(function, /* parameterIndex */i);
            LLVMBuildStore(builder, param, pointer);
        }
    }

    @Override
    public Pointer visitConstDef(SysYParser.ConstDefContext ctx) {
        //赋值前需要填好values
        this.visitChildren(ctx);
        printTest("visitVarDef");
        if (ctx.L_BRACKT().size() != 0) {
            //int 数组声明
            arrayDef(ctx);
        } else {
            //int 声明
            intDef(ctx);
        }
        return null;
    }

    private void arrayDef(SysYParser.ConstDefContext ctx) {
        String varName = ctx.IDENT().getText();
        //获取元素个数 int i[1+1]
        int numOfElements = valueOfValues.get(ctx.constExp(0).exp());
        //System.out.println(numOfElements);
        LLVMValueRef pointer = null;
        if (currentScope.getEnclosingScope() == null) {
            //创建名为globalVar的全局变量
            pointer = LLVMAddGlobal(module, LLVMArrayType(i32Type, numOfElements), /*globalVarName:String*/"globalVar");
        } else {
            pointer = LLVMBuildAlloca(builder, LLVMArrayType(i32Type, numOfElements), varName);
        }

        //写入向量表
        currentScope.define(varName, pointer);
        //给数组每一个元素赋值
        List<LLVMValueRef> refs = new ArrayList<>();
        for (int i = 0; i < numOfElements; i++) {
            //取出每个元素，如果没有填写，默认为0
            int value = 0;
            LLVMValueRef llvmValueRef = null;
            //判断是否为int a[2] 或int a[2]={b[1]}
            if (ctx.constInitVal() != null && i < ctx.constInitVal().constInitVal().size() && ctx.constInitVal().constInitVal(i).constExp().exp() instanceof SysYParser.NumberExpContext) {
                value = valueOfValues.get(ctx.constInitVal().constInitVal(i).constExp().exp());
                llvmValueRef = LLVMConstInt(i32Type, value, 0);
            } else if (ctx.constInitVal() != null && i < ctx.constInitVal().constInitVal().size() && ctx.constInitVal().constInitVal(i).constExp().exp() instanceof SysYParser.LvalExpContext) {
                //int a[2]={b[1]}
                llvmValueRef = (LLVMValueRef) values.get(ctx.constInitVal().constInitVal(i).constExp().exp());
            } else {
                llvmValueRef = LLVMConstInt(i32Type, value, 0);
            }
            PointerPointer<LLVMValueRef> pointerPointer = new PointerPointer<>(LLVMConstInt(LLVMInt32Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), i, 0));
            LLVMValueRef arrayElement = LLVMBuildGEP(builder, pointer, pointerPointer, 2, "arrayElement");
            refs.add(llvmValueRef);
            //将数值存入该内存
            if (currentScope.getEnclosingScope() == null) {
                continue;
            } else {
                LLVMBuildStore(builder, llvmValueRef, arrayElement);
            }
        }
        //全局数组实现：
        if (currentScope.getEnclosingScope() == null) {
            PointerPointer globalArrayP = new PointerPointer<>(refs.toArray(new LLVMValueRef[]{}));
            LLVMValueRef result = LLVMConstArray(i32Type, globalArrayP, numOfElements);
            LLVMSetInitializer(pointer, result);
        }
    }


    private void intDef(SysYParser.ConstDefContext ctx) {
        //llvm处理和符号表处理
        LLVMValueRef pointer = null;
        if (currentScope.getEnclosingScope() == null) {
            //创建名为globalVar的全局变量
            pointer = LLVMAddGlobal(module, i32Type, /*globalVarName:String*/"globalVar");
        } else {
            pointer = LLVMBuildAlloca(builder, i32Type, /*pointerName:String*/"int");
        }
        currentScope.define(ctx.IDENT().getText(), pointer);
        if (ctx.ASSIGN() != null) {
            //const int a=1
            LLVMValueRef number = (LLVMValueRef) values.get(ctx.constInitVal().constExp().exp());
            if (currentScope.getEnclosingScope() == null) {
                //为全局变量设置初始化器
                LLVMSetInitializer(pointer, /* constantVal:LLVMValueRef*/number);
            } else {
                //申请一块能存放int型的内存
                //将数值存入该内存
                LLVMBuildStore(builder, number, pointer);
            }
        }
    }

    @Override
    public Pointer visitVarDef(SysYParser.VarDefContext ctx) {
        //赋值前需要填好values
        this.visitChildren(ctx);

        printTest("visitVarDef");
        if (ctx.L_BRACKT().size() != 0) {
            //int 数组声明
            arrayDef(ctx);
        } else {
            //int 声明
            intDef(ctx);
        }
        return null;
    }

    private void arrayDef(SysYParser.VarDefContext ctx) {
        String varName = ctx.IDENT().getText();
        int numOfElements = valueOfValues.get(ctx.constExp(0).exp());
        LLVMValueRef pointer = null;
        if (currentScope.getEnclosingScope() == null) {
            //创建名为globalVar的全局变量
            pointer = LLVMAddGlobal(module, LLVMArrayType(i32Type, numOfElements), /*globalVarName:String*/"globalVar");
        } else {
            pointer = LLVMBuildAlloca(builder, LLVMArrayType(i32Type, numOfElements), varName);
        }
        //写入向量表
        currentScope.define(varName, pointer);
        //给数组每一个元素赋值
        List<LLVMValueRef> refs = new ArrayList<>();
        for (int i = 0; i < numOfElements; i++) {
            //取出每个元素，如果没有填写，默认为0
            int value = 0;
            LLVMValueRef llvmValueRef = null;
            //判断是否为int a[2] 或int a[2]={b[1]}
            if (ctx.initVal() != null && i < ctx.initVal().initVal().size() && ctx.initVal().initVal(i).exp() instanceof SysYParser.NumberExpContext) {
                value = valueOfValues.get(ctx.initVal().initVal(i).exp());
                llvmValueRef = LLVMConstInt(i32Type, value, 0);
            } else if (ctx.initVal() != null && i < ctx.initVal().initVal().size() && ctx.initVal().initVal(i).exp() instanceof SysYParser.LvalExpContext) {
                //int a[2]={b[1]}
                llvmValueRef = (LLVMValueRef) values.get(ctx.initVal().initVal(i).exp());
            } else {
                llvmValueRef = LLVMConstInt(i32Type, value, 0);
            }
            PointerPointer<LLVMValueRef> pointerPointer = new PointerPointer<>(LLVMConstInt(LLVMInt32Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), i, 0));
            LLVMValueRef arrayElement = LLVMBuildGEP(builder, pointer, pointerPointer, 2, "arrayElement");

            refs.add(llvmValueRef);
            //将数值存入该内存
            if (currentScope.getEnclosingScope() == null) {
                continue;
            } else {
                LLVMBuildStore(builder, llvmValueRef, arrayElement);
            }
        }
        if (currentScope.getEnclosingScope() == null) {
            System.out.println(refs);
            PointerPointer globalArrayP = new PointerPointer<>(refs.toArray(new LLVMValueRef[]{}));
            LLVMValueRef result = LLVMConstArray(i32Type, globalArrayP, numOfElements);
            LLVMSetInitializer(pointer, result);
        }
    }


    private void intDef(SysYParser.VarDefContext ctx) {
        //llvm处理和符号表处理
        LLVMValueRef pointer = null;
        if (currentScope.getEnclosingScope() == null) {
            //创建名为globalVar的全局变量
            pointer = LLVMAddGlobal(module, i32Type, /*globalVarName:String*/"globalVar");
        } else {
            pointer = LLVMBuildAlloca(builder, i32Type, /*pointerName:String*/"int");
        }
        currentScope.define(ctx.IDENT().getText(), pointer);
        //判断是int a=1还是int a
        if (ctx.ASSIGN() != null) {
            // int a=1
            LLVMValueRef number = (LLVMValueRef) values.get(ctx.initVal().exp());
            if (currentScope.getEnclosingScope() == null) {
                //为全局变量设置初始化器
                LLVMSetInitializer(pointer, /* constantVal:LLVMValueRef*/number);
            } else {
                //申请一块能存放int型的内存
                //将数值存入该内存
                LLVMBuildStore(builder, number, pointer);
            }
        } else {
            //int a
            if (currentScope.getEnclosingScope() == null) {
                //为全局变量设置初始化器
                LLVMSetInitializer(pointer, /* constantVal:LLVMValueRef*/LLVMConstInt(i32Type, 0, 0));
            }
        }
    }

    @Override
    public Pointer visitReturnStmt(SysYParser.ReturnStmtContext ctx) {
        //先计算子节点exp
        visitChildren(ctx);
        //函数返回指令
        LLVMValueRef result = (LLVMValueRef) values.get(ctx.exp());
        //如果函数返回void则result为null
        if (getFuncType(ctx).equals("void")) {
            result = null;
        }
        LLVMBuildRet(builder, /*result:LLVMValueRef*/result);
        return null;
    }

    private String getFuncType(SysYParser.ReturnStmtContext ctx) {
        ParserRuleContext parentCtx = ctx;
        do {
            parentCtx = parentCtx.getParent();
        } while (!(parentCtx instanceof SysYParser.FuncDefContext));
        String result = ((SysYParser.FuncDefContext) parentCtx).funcType().getText();
        return result;
    }

    @Override
    public Pointer visitPlusExp(SysYParser.PlusExpContext ctx) {
        //先计算子节点的值
        visitChildren(ctx);
        int valueOfResult = 0;
        int valueOfLVal = 1;
        int valueOfRVal = 1;
        if (valueOfValues.get(ctx.exp(0)) != null) {
            valueOfLVal = valueOfValues.get(ctx.exp(0));
        }
        if (valueOfValues.get(ctx.exp(1)) != null) {
            valueOfRVal = valueOfValues.get(ctx.exp(1));
        }
        LLVMValueRef lVal = (LLVMValueRef) values.get(ctx.exp(0));
        LLVMValueRef rVal = (LLVMValueRef) values.get(ctx.exp(1));
        LLVMValueRef result = null;
        if (ctx.PLUS() != null) {
            //创建add指令并将结果保存在一个临时变量中
            valueOfResult = valueOfLVal + valueOfRVal;
            result = LLVMBuildNSWAdd(builder, lVal, rVal, /* varName:String */"plusResult");
        } else {
            valueOfResult = valueOfLVal - valueOfRVal;
            result = LLVMBuildNSWSub(builder, lVal, rVal, /* varName:String */"subResult");
        }
        values.put(ctx, result);
        valueOfValues.put(ctx, valueOfResult);
        return null;
    }

    @Override
    public Pointer visitMulExp(SysYParser.MulExpContext ctx) {
        visitChildren(ctx);
        LLVMValueRef lVal = (LLVMValueRef) values.get(ctx.exp(0));
        LLVMValueRef rVal = (LLVMValueRef) values.get(ctx.exp(1));
        int valueOfResult = 0;
        int valueOfLVal = 1;
        int valueOfRVal = 1;
        if (valueOfValues.get(ctx.exp(0)) != null) {
            valueOfLVal = valueOfValues.get(ctx.exp(0));
        }
        if (valueOfValues.get(ctx.exp(1)) != null) {
            valueOfRVal = valueOfValues.get(ctx.exp(1));
        }
        LLVMValueRef result = null;
        if (ctx.MUL() != null) {
            valueOfResult = valueOfLVal * valueOfRVal;
            result = LLVMBuildNSWMul(builder, lVal, rVal, /* varName:String */"plusResult");
        } else if (ctx.DIV() != null) {
            valueOfResult = valueOfLVal / valueOfRVal;
            result = LLVMBuildSDiv(builder, lVal, rVal, /* varName:String */"divResult");
        } else {
            valueOfResult = valueOfLVal % valueOfRVal;
            result = LLVMBuildSRem(builder, lVal, rVal, /* varName:String */"remResult");
        }
        values.put(ctx, result);
        valueOfValues.put(ctx, valueOfResult);
        return null;
    }

    @Override
    public Pointer visitUnaryOpExp(SysYParser.UnaryOpExpContext ctx) {
        visitChildren(ctx);
        LLVMValueRef lVal = (LLVMValueRef) values.get(ctx.exp());
        int valueOfResult = 0;
        if (valueOfValues.get(ctx.exp()) != null) {
            valueOfResult = valueOfValues.get(ctx.exp());
        }
        LLVMValueRef result = null;
        if (ctx.unaryOp().MINUS() != null) {
            valueOfResult = -valueOfResult;
            LLVMValueRef zero = LLVMConstInt(i32Type, 0, /* signExtend */ 0);
            result = LLVMBuildNSWSub(builder, zero, lVal, /* varName:String */"reverseResult");
        } else {
            //！a:
            //%4 = icmp ne i32 %3, 0
            //%5 = xor i1 %4, true
            //%6 = zext i1 %5 to i32
            // 生成icmp
            lVal = LLVMBuildICmp(builder, LLVMIntNE, lVal, LLVMConstInt(i32Type, 0, 0), "icmp");
            // 生成xor
            lVal = LLVMBuildXor(builder, lVal, LLVMConstInt(LLVMInt1Type(), 1, 0), "xor");
            // 生成zext
            result = LLVMBuildZExt(builder, lVal, i32Type, "zext");
            if (valueOfResult == 0) {
                valueOfResult = 1;
            } else {
                valueOfResult = 0;
            }
        }
        values.put(ctx, result);
        valueOfValues.put(ctx, valueOfResult);
        return null;
    }

    @Override
    public Pointer visitLvalExp(SysYParser.LvalExpContext ctx) {
        visitChildren(ctx);
        LLVMValueRef lVal = (LLVMValueRef) currentScope.resolve(ctx.lVal().IDENT().getText());
        //从内存中将值取出
        LLVMValueRef value;
        if (ctx.lVal().L_BRACKT().size() != 0) {
            //数组取值
            //index:数组偏移量
            LLVMValueRef llvmValueRef = (LLVMValueRef) values.get(ctx.lVal().exp(0));
            //GEP取节点
            PointerPointer<LLVMValueRef> pointerPointer = new PointerPointer<>(LLVMConstInt(LLVMInt32Type(), 0, 0), llvmValueRef);
            lVal = LLVMBuildGEP(builder, lVal, pointerPointer, 2, "res");
        }
        //System.err.println(ctx.lVal().IDENT().getText());
        value = LLVMBuildLoad(builder, lVal, /*varName:String*/"load");
        values.put(ctx, value);
        return null;
    }

    @Override
    public Pointer visitNumberExp(SysYParser.NumberExpContext ctx) {
        //将常数值转化为LLVMConst，提取到values中
        int number = myParseInt(ctx.number().getText());
        LLVMValueRef result = LLVMConstInt(i32Type, number, 0);
        values.put(ctx, result);
        valueOfValues.put(ctx, number);
        return null;
    }

    private int myParseInt(String text) {
        text = IntegerCorrextion(text);
        return Integer.parseInt(text);
    }

    @Override
    public Pointer visitCallFuncExp(SysYParser.CallFuncExpContext ctx) {
        visitChildren(ctx);
        String funcName = ctx.IDENT().getText();
        LLVMValueRef function = (LLVMValueRef) currentScope.resolve(funcName);
        //提取参数
        int numOfParams = 0;
        if (ctx.funcRParams() != null) {
            numOfParams = ctx.funcRParams().param().size();
        }
        LLVMValueRef[] params = new LLVMValueRef[numOfParams];

        for (int i = 0; i < numOfParams; i++) {
            LLVMValueRef param = (LLVMValueRef) values.get(ctx.funcRParams().param(i).exp());
            params[i] = param;
        }
        PointerPointer<LLVMValueRef> paramsPointer = new PointerPointer(params);

        LLVMValueRef funcRes = LLVMBuildCall(builder, function, paramsPointer, numOfParams, "");
        values.put(ctx, funcRes);
        return null;
    }

    @Override
    public Pointer visitAssignStmt(SysYParser.AssignStmtContext ctx) {
        this.visitChildren(ctx);
        String varName = ctx.lVal().IDENT().getText();
        LLVMValueRef lVar = (LLVMValueRef) currentScope.resolve(varName);

        //判断是否为数组赋值
        if (ctx.lVal().L_BRACKT().size() != 0) {
            //数组
            //index:数组偏移量
            LLVMValueRef llvmValueRef = (LLVMValueRef) values.get(ctx.lVal().exp(0));
            //GEP取节点
//            PointerPointer<LLVMValueRef> pointerPointer = new PointerPointer<>(LLVMConstInt(LLVMInt32Type(), 0, 0), llvmValueRef);
//            lVar = LLVMBuildGEP(builder, lVar, pointerPointer, 2, "ArrayElement");
            PointerPointer<LLVMValueRef> pointerPointer = new PointerPointer<>(, 0, 0));
            lVar = LLVMBuildGEP(builder, lVar, pointerPointer, 1, "ArrayElement");
        }
        LLVMValueRef rVar = (LLVMValueRef) values.get(ctx.exp());
        //将数值存入该内存
        LLVMBuildStore(builder, rVar, lVar);
        return null;
    }

    @Override
    public Pointer visitExpParenthesis(SysYParser.ExpParenthesisContext ctx) {
        visitChildren(ctx);
        values.put(ctx, values.get(ctx.exp()));
        valueOfValues.put(ctx, valueOfValues.get(ctx.exp()));
        return null;
    }

    @Override
    public Pointer visitBlockStmt(SysYParser.BlockStmtContext ctx) {
        visitChildren(ctx);
        blockValue.put(ctx, blockValue.get(ctx.block()));
        return null;
    }

    //获取当前语句所处的block，要么为本函数起始block，要么为{}后的nextBlock,blockItem是可能创造nextBlock的
    @Override
    public Pointer visitConditionStmt(SysYParser.ConditionStmtContext ctx) {
        //建立while if-else语句结束后的Block
        LLVMValueRef function = this.getFunc(ctx);
        LLVMBasicBlockRef nextBlock = LLVMAppendBasicBlock(function, /*blockName:String*/"nextBlock");
        blockValue.put(ctx, nextBlock);
        //当前block
        BlockInBlock blockInBlock = blockInBlocks.get(ctx.getParent().getParent());
        LLVMBasicBlockRef mainBlock;
        if (blockInBlock == null) {
            //说明其父节点可能也是一个if()语句
            mainBlock = (LLVMBasicBlockRef) currentScope.resolve("block");
        } else {
            mainBlock = blockInBlock.getBlock();
            blockInBlock.setBlock(nextBlock);
        }
        //如果非blockStmt则为一句话,需要额外给其增加Block
        LLVMBasicBlockRef ifTrue;
        LLVMBasicBlockRef ifFalse;
        if (ctx.stmt(0) instanceof SysYParser.BlockStmtContext) {
            visit(ctx.stmt(0));
            ifTrue = blockValue.get(ctx.stmt(0));
        } else {
            //一句话block
            ifTrue = LLVMAppendBasicBlock(function, "OneSentenceTrue");
            LLVMPositionBuilderAtEnd(builder, ifTrue);
            currentScope = new BaseScope("OneSentenceTScope", currentScope);
            currentScope.define("block", ifTrue);
            visit(ctx.stmt(0));
            currentScope = currentScope.getEnclosingScope();
            LLVMBuildBr(builder, nextBlock);
            LLVMPositionBuilderAtEnd(builder, mainBlock);
        }
        if (ctx.stmt().size() == 2) {
            if (ctx.stmt(1) instanceof SysYParser.BlockStmtContext) {
                visit(ctx.stmt(1));
                ifFalse = (ctx.stmt().size() == 2) ? blockValue.get(ctx.stmt(1)) : nextBlock;
            } else {
                ifFalse = LLVMAppendBasicBlock(function, "OneSentenceFalse");
                LLVMPositionBuilderAtEnd(builder, ifFalse);
                currentScope = new BaseScope("OneSentenceFScope", currentScope);
                currentScope.define("block", ifFalse);
                visit(ctx.stmt(1));
                currentScope = currentScope.getEnclosingScope();
                LLVMBuildBr(builder, nextBlock);
                LLVMPositionBuilderAtEnd(builder, mainBlock);
            }
        } else {
            ifFalse = nextBlock;
        }
        falseBlock.put(ctx, ifFalse);
        trueBlock.put(ctx, ifTrue);
        LLVMPositionBuilderAtEnd(builder, mainBlock);
        visit(ctx.cond());
        LLVMPositionBuilderAtEnd(builder, nextBlock);
        return null;
    }

    @Override
    public Pointer visitEqCond(SysYParser.EqCondContext ctx) {
        visitChildren(ctx);
        LLVMValueRef lVal = (LLVMValueRef) values.get(ctx.cond(0));
        LLVMValueRef rVal = (LLVMValueRef) values.get(ctx.cond(1));
        LLVMValueRef condition;
        if (ctx.EQ() != null) {
            condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntEQ, lVal, rVal, "a == b");
        } else {
            condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntNE, lVal, rVal, "a != b");
        }
        values.put(ctx, condition);
        //条件跳转指令，选择跳转到哪个块
        buildBr(ctx, condition);
        return null;
    }

    @Override
    public Pointer visitLtCond(SysYParser.LtCondContext ctx) {
        trueBlock.put(ctx, trueBlock.get(ctx.getParent()));
        falseBlock.put(ctx, falseBlock.get(ctx.getParent()));
        visitChildren(ctx);
        LLVMValueRef lVal = (LLVMValueRef) values.get(ctx.cond(0));
        LLVMValueRef rVal = (LLVMValueRef) values.get(ctx.cond(1));
        LLVMValueRef condition = null;
        if (ctx.LT() != null) {
            condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntSLT, lVal, rVal, "a < b");
        } else if (ctx.LE() != null) {
            condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntSLE, lVal, rVal, "a <= b");
        } else if (ctx.GT() != null) {
            condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntSGT, lVal, rVal, "a > b");
        } else if (ctx.GE() != null) {
            condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntSGE, lVal, rVal, "a >= b");
        }

        if (!(ctx.getParent() instanceof SysYParser.LtCondContext)) {
            buildBr(ctx, condition);
        } else {
            LLVMValueRef tmp = LLVMBuildZExt(builder, condition, i32Type, "tmp");
            values.put(ctx, tmp);
        }
        return null;
    }

    private void buildBr(ParserRuleContext ctx, LLVMValueRef condition) {

        LLVMBasicBlockRef ifTrue = getTrue(ctx);
        LLVMBasicBlockRef ifFalse = getFalse(ctx);
        LLVMBuildCondBr(builder,
                /*condition:LLVMValueRef*/ condition,
                /*ifTrue:LLVMBasicBlockRef*/ ifTrue,
                /*ifFalse:LLVMBasicBlockRef*/ ifFalse);
    }

    private LLVMBasicBlockRef getTrue(ParserRuleContext ctx) {
        LLVMBasicBlockRef ifTrue = trueBlock.get(ctx.getParent());
        if (ctx.getParent() instanceof SysYParser.AndCondContext && ctx.getParent().getChild(2).equals(ctx)) {
            //说明在AND的右侧
            ifTrue = trueBlock.get(ctx.getParent().getParent());
        }
        return ifTrue;
    }

    private LLVMBasicBlockRef getFalse(ParserRuleContext ctx) {
        LLVMBasicBlockRef ifFalse = falseBlock.get(ctx.getParent());
        if (ctx.getParent() instanceof SysYParser.OrCondContext && ctx.getParent().getChild(2).equals(ctx)) {
            //说明在OR的右侧
            ifFalse = falseBlock.get(ctx.getParent().getParent());
        }
        return ifFalse;
    }

    @Override
    public Pointer visitOrCond(SysYParser.OrCondContext ctx) {
        //建立block
        trueBlock.put(ctx, trueBlock.get(ctx.getParent()));
        LLVMBasicBlockRef ifFalse = LLVMAppendBasicBlock(getFunc(ctx), "orFalse");
        falseBlock.put(ctx, ifFalse);
        visit(ctx.cond(0));
        LLVMPositionBuilderAtEnd(builder, ifFalse);
        visit(ctx.cond(1));
        return null;
    }

    @Override
    public Pointer visitAndCond(SysYParser.AndCondContext ctx) {
        //建立block
        falseBlock.put(ctx, falseBlock.get(ctx.getParent()));
        //trueBlock是and的右侧
        LLVMBasicBlockRef ifTrue = LLVMAppendBasicBlock(getFunc(ctx), "andTrue");
        trueBlock.put(ctx, ifTrue);
        visit(ctx.cond(0));
        LLVMPositionBuilderAtEnd(builder, ifTrue);
        visit(ctx.cond(1));
        return null;
    }

    @Override
    public Pointer visitExpCond(SysYParser.ExpCondContext ctx) {
        visitChildren(ctx);
        values.put(ctx, values.get(ctx.exp()));
        //if(a)或者if(a&&b)
        ParserRuleContext parent = ctx.getParent();
        //创建一个常量,这里是常数0
        LLVMValueRef zero = LLVMConstInt(i32Type, 0, /* signExtend */ 0);
        if (parent instanceof SysYParser.AndCondContext || parent instanceof SysYParser.OrCondContext || parent instanceof SysYParser.ConditionStmtContext || parent instanceof SysYParser.WhileStmtContext) {
            LLVMValueRef condition = LLVMBuildICmp(builder, /*这是个int型常量，表示比较的方式*/LLVMIntNE, (LLVMValueRef) values.get(ctx), zero, "condition = n == 0");
            buildBr(ctx, condition);
        }
        return null;
    }

    private void printTest(String s) {
        //System.out.println(s);
    }

    @Override
    public Pointer visitWhileStmt(SysYParser.WhileStmtContext ctx) {
        //建立while语句结束后运行的Block vs while语句结束后语句的block
        LLVMValueRef function = this.getFunc(ctx);
        LLVMBasicBlockRef nextBlock = LLVMAppendBasicBlock(function, /*blockName:String*/"nextBlock");
        whileNextBlock.put(ctx, nextBlock);
        LLVMBasicBlockRef conditionBlock = LLVMAppendBasicBlock(function, "conditionBlock");
        blockValue.put(ctx, conditionBlock);
        //当前block
        BlockInBlock blockInBlock = blockInBlocks.get(ctx.getParent().getParent());
        LLVMBasicBlockRef mainBlock;
        if (blockInBlock == null) {
            //说明其父节点可能也是一个while,if()语句
            mainBlock = (LLVMBasicBlockRef) currentScope.resolve("block");
        } else {
            mainBlock = blockInBlock.getBlock();
            blockInBlock.setBlock(nextBlock);
        }
        //如果非blockStmt则为一句话,需要额外给其增加Block
        LLVMBasicBlockRef ifTrue;
        LLVMBasicBlockRef ifFalse = nextBlock;
        if (ctx.stmt() instanceof SysYParser.BlockStmtContext) {
            visit(ctx.stmt());
            ifTrue = blockValue.get(ctx.stmt());
        } else {
            //一句话block
            ifTrue = LLVMAppendBasicBlock(function, "OneSentenceTrue");
            LLVMPositionBuilderAtEnd(builder, ifTrue);
            currentScope = new BaseScope("OneSentenceTScope", currentScope);
            currentScope.define("block", ifTrue);
            visit(ctx.stmt());
            currentScope = currentScope.getEnclosingScope();
            LLVMBuildBr(builder, nextBlock);
            LLVMPositionBuilderAtEnd(builder, mainBlock);
        }
        falseBlock.put(ctx, ifFalse);
        trueBlock.put(ctx, ifTrue);
        LLVMPositionBuilderAtEnd(builder, mainBlock);
        //跳转到一个新的ConditionBlock
        LLVMBuildBr(builder, conditionBlock);
        LLVMPositionBuilderAtEnd(builder, conditionBlock);
        visit(ctx.cond());
        LLVMPositionBuilderAtEnd(builder, nextBlock);
        return null;
    }

    @Override
    public Pointer visitBreakStmt(SysYParser.BreakStmtContext ctx) {
        SysYParser.WhileStmtContext whileStmtContext = getParentWhile(ctx);
        LLVMBasicBlockRef nextBlock = whileNextBlock.get(whileStmtContext);
        LLVMBuildBr(builder, nextBlock);
        return null;
    }

    @Override
    public Pointer visitContinueStmt(SysYParser.ContinueStmtContext ctx) {
        SysYParser.WhileStmtContext whileStmtContext = getParentWhile(ctx);
        LLVMBasicBlockRef conditionBlock = blockValue.get(whileStmtContext);
        LLVMBuildBr(builder, conditionBlock);
        return null;
    }

    public SysYParser.WhileStmtContext getParentWhile(ParserRuleContext ctx) {
        do {
            ctx = ctx.getParent();
        } while (!(ctx instanceof SysYParser.WhileStmtContext));
        return (SysYParser.WhileStmtContext) ctx;
    }

    //该私有类专门记录函数block中{}以外的block
    //应对例如:
//   if(exp)
//       exp
//    if(exp)
//        exp
    //挂载在block node
    private class BlockInBlock {
        private List<LLVMBasicBlockRef> blockList = new ArrayList<>();
        private int current = 0;

        public BlockInBlock(LLVMBasicBlockRef block) {
            blockList.add(block);
        }

        public void setBlock(LLVMBasicBlockRef llvmBasicBlockRef) {
            blockList.add(llvmBasicBlockRef);
        }

        public LLVMBasicBlockRef getBlock() {
            return blockList.get(current++);
        }
    }
}

